# DjangoDE, an integrated development environment for Django
# Copyright (C) 2010-2011 Andrew Wilkinson
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

import sys
import unittest

from djangode import global_objects
from djangode.gui import MainWindow
from djangode.gui.python_editor import PythonEditor
from djangode.utils.qt import Qt, QtCore, QtGui

class TestPythonEditorAutoCompleter(unittest.TestCase):
    def setUp(self):
        if hasattr(sys, "last_type"):
            del sys.last_type

        global_objects.main_window = MainWindow()

    def tearDown(self):
        global_objects.main_window.close()
        global_objects.main_window = None

    def test_new_file(self):
        tab_count = global_objects.main_window.editor.count()

        global_objects.main_window.actions["new_file"].trigger()

        self.assert_(global_objects.main_window.editor.count() == tab_count + 1, global_objects.main_window.editor.count())

    def test_keypress(self):
        """Check that a key press is sent to the PythonEditor."""
        global_objects.main_window.actions["new_file"].trigger()
        editor = global_objects.main_window.editor.widget(0)
        editor.setFocus(QtCore.Qt.OtherFocusReason)

        self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, ord("A"), QtCore.Qt.NoModifier, "A"))

        self.assert_(not hasattr(sys, "last_type")) # Check that there were no exceptions while processing events.
        self.assert_(unicode(editor.document().toPlainText()).strip() == "A", unicode(editor.document().toPlainText()))

    def test_import_autocomplete(self):
        global_objects.main_window.actions["new_file"].trigger()
        editor = global_objects.main_window.editor.widget(0)
        editor.setFocus(QtCore.Qt.OtherFocusReason)

        for char in "import ":
            self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, ord(char), QtCore.Qt.NoModifier, char))

        self.assert_(not hasattr(sys, "last_type")) # Check that there were no exceptions while processing events.
        self.assert_(editor.completer.popup().isVisible())

        editor.completer.setCompletionPrefix("django")
        self.assert_(editor.completer.currentCompletion() == "django")

    def test_import_no_complete_for_invalid_submodule(self):
        """
        Test that when you type something like 'import invalid_module_name.' that you don't get a completion box.
        """
        global_objects.main_window.actions["new_file"].trigger()
        editor = global_objects.main_window.editor.widget(0)
        editor.setFocus(QtCore.Qt.OtherFocusReason)

        for char in "import invalid_module_name.":
            self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, ord(char), QtCore.Qt.NoModifier, char))
        global_objects.app.processEvents()

        self.assert_(not hasattr(sys, "last_type")) # Check that there were no exceptions while processing events.
        self.assert_(not editor.completer.popup().isVisible())

    def test_import_no_complete_after_space(self):
        """
        Test that when you type something like 'import django as dj' that you don't get a completion box after typing 'django '.
        """
        global_objects.main_window.actions["new_file"].trigger()
        editor = global_objects.main_window.editor.widget(0)
        editor.setFocus(QtCore.Qt.OtherFocusReason)

        for char in "import django ":
            self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, ord(char), QtCore.Qt.NoModifier, char))

        self.assert_(not hasattr(sys, "last_type")) # Check that there were no exceptions while processing events.
        self.assert_(not editor.completer.popup().isVisible())

    def test_from_import_module_autocomplete(self):
        """
        Test that when you type something like 'from django import utils' that you get a completion box after typing 'from '.
        """
        global_objects.main_window.actions["new_file"].trigger()
        editor = global_objects.main_window.editor.widget(0)
        editor.setFocus(QtCore.Qt.OtherFocusReason)

        for char in "from ":
            self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, ord(char), QtCore.Qt.NoModifier, char))

        self.assert_(not hasattr(sys, "last_type")) # Check that there were no exceptions while processing events.
        self.assert_(editor.completer.popup().isVisible())

        editor.completer.setCompletionPrefix("django")
        self.assert_(editor.completer.currentCompletion() == "django")

    def test_from_import_module_contents_autocomplete(self):
        """
        Test that when you type something like 'from django import utils' that you get a completion box after typing 'from django import '.
        """
        global_objects.main_window.actions["new_file"].trigger()
        editor = global_objects.main_window.editor.widget(0)
        editor.setFocus(QtCore.Qt.OtherFocusReason)

        for char in "from django import ":
            self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, ord(char), QtCore.Qt.NoModifier, char))

        self.assert_(not hasattr(sys, "last_type")) # Check that there were no exceptions while processing events.
        self.assert_(editor.completer.popup().isVisible())

        editor.completer.setCompletionPrefix("VERSION")
        self.assert_(editor.completer.currentCompletion() == "VERSION")

    def test_from_import_module_contents_autocomplete_after_delete(self):
        """
        Test that when you type something like 'from django.utils.cache import ', and then change it to 'from django.conf import '
        that you get a completion box with the new details.
        """
        global_objects.main_window.actions["new_file"].trigger()
        editor = global_objects.main_window.editor.widget(0)
        editor.setFocus(QtCore.Qt.OtherFocusReason)

        for char in "from django.utils.cache import ":
            self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, ord(char), QtCore.Qt.NoModifier, char))

        self.assert_(not hasattr(sys, "last_type")) # Check that there were no exceptions while processing events.
        self.assert_(editor.completer.popup().isVisible())

        for i in range(len("utils.cache import ")):
            self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Backspace, QtCore.Qt.NoModifier, ""))

        for char in "conf import ":
            self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, ord(char), QtCore.Qt.NoModifier, char))

        editor.completer.setCompletionPrefix("ENVIRONMENT_VARIABLE")
        self.assert_(editor.completer.currentCompletion() == "ENVIRONMENT_VARIABLE")

    def test_module_variable_contents_autocomplete(self):
        """
        Test that when you type something like 'django.' that you get a completion box.
        """
        global_objects.main_window.actions["new_file"].trigger()
        editor = global_objects.main_window.editor.widget(0)
        editor.setFocus(QtCore.Qt.OtherFocusReason)

        for char in "import django":
            self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, ord(char), QtCore.Qt.NoModifier, char))
        self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, 0x1000004, QtCore.Qt.NoModifier)) # QtCore.Qt.Key_Return
        self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, 0x1000004, QtCore.Qt.NoModifier))
        for char in "django.":
            self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, ord(char), QtCore.Qt.NoModifier, char))

        self.assert_(not hasattr(sys, "last_type")) # Check that there were no exceptions while processing events.
        self.assert_(editor.completer.popup().isVisible())

        editor.completer.setCompletionPrefix("VERSION")
        self.assert_(editor.completer.currentCompletion() == "VERSION")

    def test_undefined_variable(self):
        """
        Test that when you type something like 'x.' without defining 'x' no exceptions raised.
        """
        global_objects.main_window.actions["new_file"].trigger()
        editor = global_objects.main_window.editor.widget(0)
        editor.setFocus(QtCore.Qt.OtherFocusReason)

        for char in "x.":
            self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, ord(char), QtCore.Qt.NoModifier, char))

        self.assert_(not hasattr(sys, "last_type")) # Check that there were no exceptions while processing events.
        self.assert_(not editor.completer.popup().isVisible())

    def test_autocomplete_class_methods(self):
        """
        Test that class methods are autocompleted.
        """
        global_objects.main_window.actions["new_file"].trigger()
        editor = global_objects.main_window.editor.widget(0)
        editor.setFocus(QtCore.Qt.OtherFocusReason)

        code = """
class Test:
    def add(self, x):
        return x
    def delete(self, x):
        return x
t = Test()
t."""

        for char in code:
            if char == "\n":
                self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, 0x1000004, QtCore.Qt.NoModifier)) # QtCore.Qt.Key_Return
            else:
                self.send_event(editor, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, ord(char), QtCore.Qt.NoModifier, char))

        self.assert_(not hasattr(sys, "last_type")) # Check that there were no exceptions while processing events.
        self.assert_(editor.completer.popup().isVisible())

        editor.completer.setCompletionPrefix("add")
        self.assert_(editor.completer.currentCompletion() == "add")

    def send_event(self, editor, event):
        global_objects.app.sendEvent(editor.completer.popup() if editor.completer.popup().isVisible() else editor, event)
        global_objects.app.processEvents()
